function compileMapController(self)
{
    self.MapController = Class.create(
    {
    	/**
    	 * Search timeout of 10 seconds.
    	 */
    	SEARCH_TIMEOUT: 10000,
    	
        /**
         * Constructor.
         * 
         * @param mapContainerRange The range of coordinates specifying the size of the map container.
         * @param hidden Whether or not the page is initially hidden.
         * @param mapSearchInputId The map search input ID.
         * @param mapSearchButtonId The search button ID.
         * @param containerDivId The entire map container.
         * @param disabledContainerDivId The disabled container.
         * @param searchDivId The search input area.
         * @param canvasDivId The canvas onto which the map is drawn.
         * @param textInfoDivId The text info area.
         * @param locationListPageRange The range of coordinates specifying the size of the location list page.
         * @param locationListPageId The location list page.
         * @param locationListHeadId The location list page head.
         * @param locationListBodyId The location list page body.
         * @param locationListCloseId The location list close area.
         * @param zoom Zoom level
         */
        initialize: function(mapContainerRange, hidden, mapSearchInputId, mapSearchButtonId, containerDivId, disabledContainerDivId, searchDivId, canvasDivId,
            textInfoDivId, locationListPageRange, locationListPageId, locationListHeadId, locationListBodyId, locationListCloseId, zoom)
        {
        	// Get reference to search inputs.
            this.searchInputTxt = jQuery('#' + mapSearchInputId);
            this.searchInputBtn = jQuery('#' + mapSearchButtonId);
            
            // Bind onclick handler to map search button.
            this.searchInputBtn.click(
               function(self)
               {
                   return function()
                   {
                   	   if (self.searchInputTxt[0].value.length != 0)
                   	   {
                   	        self.disable();
                            self.search();
                   	   }
                   };
               }(this));
               
            // Bind enter key to search input.
            this.searchInputTxt.keypress(
               function(searchInputBtn)
               {
                  return function (e)
                  {
                    if (e.which == 13)
                    {
                        searchInputBtn.click();
                        return false;
                    }
                  };
               }(this.searchInputBtn));

        	// Determine location to use.
        	var location = UserInfo.location;
        	
        	// Setup map container.
        	this.setupMapContainer(location, mapContainerRange, hidden, mapSearchInputId, mapSearchButtonId, containerDivId, disabledContainerDivId,
        	   searchDivId, canvasDivId, textInfoDivId, zoom);
        	
        	// Setup location list page.
        	this.setupLocationListPage(locationListPageRange, locationListPageId, locationListHeadId, locationListBodyId, locationListCloseId);
        },
        
        /**
         * Sets up the map container.
         * 
         * @param location The location centre of the map.
         * @param range The range of coordinates specifying the size of the map container.
         * @param hidden Whether or not the page is initially hidden.
         * @param mapSearchInputId The map search input ID.
         * @param mapSearchButtonId The search button ID.
         * @param containerDivId The entire map container.
         * @param disabledContainerDivId The disabled container.
         * @param searchDivId The search input area.
         * @param canvasDivId The canvas onto which the map is drawn.
         * @param textInfoDivId The text info area.
         * @param zoom Zoom level
         */
        setupMapContainer: function(location, range, hidden, mapSearchInputId, mapSearchButtonId, containerDivId, disabledContainerDivId, searchDivId,
            canvasDivId, textInfoDivId, zoom)
        {
        	// Create a search object.
            this.localSearch = new google.search.LocalSearch();
            this.localSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET); // Get maximum number of results.
            this.localSearch.setNoHtmlGeneration();   // Optimize for custom rendering of results.
            this.localSearch.setSearchCompleteCallback(this, MapController.prototype.searchComplete); // Setup callback for result processing.
            
            // Setup info text for map.
            var infoText;
            if (GeoLocation.method == GeoLocation.methods.GOOGLE_AJAX_API)
            {
                if (GeoLocation.ajaxReason == GeoLocation.ajaxReasons.NO_HTML5_OR_GEARS)
                {
                    infoText = Messages['NO_HTML5_OR_GEARS'];
                }
                else if (GeoLocation.ajaxReason == GeoLocation.ajaxReasons.GEARS_DENIED)
                {
                    infoText = Messages['GEARS_DENIED'];
                }
            }
            else if (location.ajaxApiUsedAsFallback)
            {
                infoText = Messages['LOCATION_ERROR'];
            }
            
            // Create map.
            this.mapContainer = new MapContainer(range, hidden, containerDivId, disabledContainerDivId, searchDivId, canvasDivId, textInfoDivId,
                location, zoom, google.maps.MapTypeId.ROADMAP, Messages['I_AM_HERE'], Messages['ARE_YOU_HERE'], infoText);
                
            // Anchor the map.
            this.mapContainer.anchorContainer();
        },
        
        /**
         * Sets up the location list page.
         * 
         * @param locationListPageRange The range of coordinates specifying the size of the location list page.
         * @param locationListPageId The location list page.
         * @param locationListHeadId The location list page head.
         * @param locationListBodyId The location list page body.
         * @param locationListCloseId The location list close area.
         */
        setupLocationListPage: function(locationListPageRange, locationListPageId, locationListHeadId, locationListBodyId, locationListCloseId)
        {
        	// Create location list page.
        	this.locationListPage = new LocationListPage(this.mapContainer, locationListPageRange, locationListPageId, locationListHeadId, locationListBodyId,
        	   locationListCloseId, 'ListRow', 'ListAlternateRow', 'LocationListColumn',
        	   function(self)
        	   {
        	   	   return function(lat, lng)
        	   	   {
        	   	   	   self.dataSelected(lat, lng);
        	   	   };
        	   }(this),
        	   function(self)
        	   {
        	   	   return function()
        	   	   {
        	   	   	   self.enable();
        	   	   };
        	   }(this));
        	   
        	// Anchor the list page.
        	this.locationListPage.anchorContainer();
        },
        
        /**
         * Search function.
         */
        search: function()
        {
        	// Setup search object.
            this.localSearch.setCenterPoint(this.mapContainer.map.getLocation());    // Centre of search results.
            
            // Perform search.
            this.localSearch.clearResults();
            this.localSearch.execute(this.searchInputTxt[0].value);
            
            // Setup search timeout.
            if (this.searchTimeoutId)
            {
            	// Cancel existing timeout.
            	clearTimeout(this.searchTimeoutId);
            }
            this.searchTimeoutId = setTimeout(
                function(self)
                {
                	return function()
                	{
                		self.searchTimeout();
                	};
                }(this), this.SEARCH_TIMEOUT);
        },
        
        /**
         * Search completed callback function.
         */
        searchComplete: function()
        {
        	// Cancel existing timeout.
            clearTimeout(this.searchTimeoutId);
        	//alert(this.searchInputTxt[0].value + " " + this.localSearch.results.length);
        	this.locationListPage.addResults(this.localSearch.results);
        	this.locationListPage.show();
        },
        
        /**
         * Disables functionality.
         */
        disable: function()
        {
        	this.searchInputTxt.attr("disabled", true);
        	this.searchInputBtn.attr("disabled", true);
        	this.mapContainer.disable();
        },
        
        /**
         * Enables functionality.
         */
        enable: function()
        {
        	this.searchInputTxt.removeAttr("disabled");
            this.searchInputBtn.removeAttr("disabled");
            this.mapContainer.enable();
        },
        
        /**
         * Callback when data selected.
         */
        dataSelected: function(lat, lng)
        {
        	var latLng = new google.maps.LatLng(lat, lng);
        	this.mapContainer.map.placeMarker(latLng, null, null, true);
        	this.locationListPage.close();
        	this.enable();
        },
       
        /**
         * Timeout function for search.
         */ 
        searchTimeout: function()
        {
        	this.locationListPage.show();
        },
        
        /**
         * Shows the map container.
         */
        show: function()
        {
        	this.mapContainer.show();
        },
        
        /**
         * Hides the map container.
         */
        hide: function()
        {
            this.mapContainer.hide();
        }
    });
}